package com.csap.framework.oauth2.security;

import cn.dev33.satoken.oauth2.logic.type.SecurityStrategy;
import com.csap.framework.util.map.CsapMap;
import com.csap.framework.util.optional.Optional;
import org.springframework.http.HttpMethod;

import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author ycf
 * @Date 2021/8/30 7:25 下午
 * @Version 1.0
 */
public interface SecurityBeanFilter {
    static <Children, T extends SecurityFilter<Children>> Optional<T> securityFilter(T securityFilter, Oauth2SecurityProperties securityConfig, boolean refresh) {
        return Optional.of(securityFilter)
                .then(i3 -> Stream.of(SecurityStrategy.authenticated,
                                SecurityStrategy.permitAll,
                                SecurityStrategy.clientToken,
                                SecurityStrategy.clientPermitAll,
                                SecurityStrategy.accessToken)
                        .forEach(i -> securityConfig
                                .getMappingPath(i)
                                .stream()
                                .flatMap(i2 -> i2.entrySet().stream().flatMap(i4 -> CsapMap.build(i4.getKey(), i4.getValue().stream()).entrySet().stream()))
                                .collect(Collectors.groupingBy(Map.Entry::getKey, Collectors.flatMapping(Map.Entry::getValue, Collectors.toSet())))
                                .forEach((k, v) -> {
                                    if (refresh) {
                                        i3.addAllRefresh(k, i, v);
                                    } else {
                                        i3.addAll(k, i, v);
                                    }
                                })))
                .when(i -> !i.containsSecurityStrategy(HttpMethod.GET, SecurityStrategy.authenticated), i -> i.addInclude("/**"))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.role, securityConfig.getSecurityStrategy(SecurityStrategy.role)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.permission, securityConfig.getSecurityStrategy(SecurityStrategy.permission)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.clientToken, securityConfig.getSecurityStrategy(SecurityStrategy.clientToken)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.clientScope, securityConfig.getSecurityStrategy(SecurityStrategy.clientScope)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.clientPermission, securityConfig.getSecurityStrategy(SecurityStrategy.clientPermission)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.clientPermitAll, securityConfig.getSecurityStrategy(SecurityStrategy.clientPermitAll)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.accessToken, securityConfig.getSecurityStrategy(SecurityStrategy.accessToken)))
                .then(i -> i.addSecurityStrategy(SecurityStrategy.accessScope, securityConfig.getSecurityStrategy(SecurityStrategy.accessScope)));
    }

    /**
     * 权限过滤处理
     *
     * @param securityFilter 权限过滤器
     * @param securityConfig 权限配置
     * @param <Children>     权限过滤器泛型
     * @return 返回实际的过滤器
     */
    static <Children, T extends SecurityFilter<Children>> Optional<T> securityFilter(T securityFilter, Oauth2SecurityProperties securityConfig) {
        return securityFilter(securityFilter, securityConfig, false);
    }
}
